﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace OttoEngineSimulation
{
    public partial class SeitenAnsichtV2 : UserControl
    {
        private enum Takt
        {
            AnsaugTakt,
            VerdichtungsTakt,
            ExplosionsTakt,
            AbsaugTakt,
            DerSelbe
        }

        private Rectangle stange;
        private Point stangenPosiOben;
        private Point stangenPosiUnten;
        private int stangenBreite = 20;
        private int stangenHoehe = 170;
        private int stangeX;
        private int stangeY;
        private float nachObenY;
        private float nachObenYAnfang;
        private float nachUntenY;
        private Takt takt;
        private float ansaugPunktY;
        private float verdichtungsPunktX;
        private float explosionsPunktY;
        private float absaubungsPunktX;

        private float winkel;

        private float nockenWelleWinkel;
        private float dreieckWinkel1;

        private float dreieckWinkel2;
        private int radius = 40;

        private float kreisMitteX = 80;
        private float kreisMitteY = 250;

        private float stangenLaenge = 130;

        #region zylinder
        Rectangle zylinderHuelle;
        private int zylinderBreite = 40;
        private int zylinderHoehe = 120;
        Point zylinderPosition;
        Point zylinderUntenRechtspkt;
        Pen zylinderFarbe = new Pen(Color.Black);
        #endregion

        #region kolben
        Point kolbenPosition;
        Size kolbenSize;
        Rectangle kolben;
        private int kolbenBreite = 40;
        private int kolbenHoehe = 20;
        #endregion

        #region nockenwelle
        RectangleF nockenWelleRechtEck;
        private int nockenWelleRadius = 70;
        private float nockenWelleMitteX;
        private float nockenWelleMitteY;
        #endregion

        #region dreieck
        private int dreieckKreisRadius = 10;
        #endregion
        RectangleF KurbelWelleRechtEck;

        public float Winkel
        {
            set { this.winkel = value; }
        }
        public float NockenWelleWinkel
        {
            set { this.nockenWelleWinkel = value; }
        }
        public float DreiEckWinkel1
        {
            set { this.dreieckWinkel1 = value; }
        }

        public float DreiEckWinkel2
        {
            set { this.dreieckWinkel2 = value; }
        }

        public SeitenAnsichtV2()
        {
            InitializeComponent();

            this.ErzeugeZylinderHuelle();
            this.ErstelleKurbelWelle();
            this.ErzeugeNockenWelle();
            this.ErstelleKolben();
            this.BerechneTaktPunkte();
            this.BerechneKreisDaten();
        }

     

        public void ErzeugeStange()
        {
            float dreieckEckPunktX = (float)(this.nockenWelleMitteX + Math.Cos(this.nockenWelleWinkel) * (this.nockenWelleRadius - 20));
            float dreieckEckPunktY = (float)(this.nockenWelleMitteY + Math.Sin(this.nockenWelleWinkel) * (this.nockenWelleRadius - 20));

            this.stangeX = (int)dreieckEckPunktX - this.stangenBreite / 2;
            this.stangeY = (int)dreieckEckPunktY - this.stangenHoehe;
            this.stangenPosiOben = new Point(this.stangeX, this.stangeY);
            this.stange = new Rectangle(this.stangenPosiOben, new Size(this.stangenBreite, this.stangenHoehe));
            this.stangenPosiUnten = new Point(this.stangeX, this.stangeY + 5);

        }

        private void BerechneKreisDaten()
        {
            List<float> liste = new List<float>();
            float nockenWelleWinkel = (150 * (float)System.Math.PI / 50) / 2;
            float nullPunkt = (float)(this.nockenWelleMitteY + Math.Sin(this.nockenWelleWinkel) * this.nockenWelleRadius);
            this.nachObenYAnfang = nullPunkt;
            float riemenkreisPunktY; //= (float)(this.nockenWelleMitteY + Math.Sin(this.nockenWelleWinkel) * this.nockenWelleRadius);
            liste.Add(nullPunkt);
            for (float i = 151; i < 360; i++)
            {
                nockenWelleWinkel = ((i) * (float)System.Math.PI / 50) / 2;
                riemenkreisPunktY = (float)(this.nockenWelleMitteY + Math.Sin(nockenWelleWinkel) * this.nockenWelleRadius);
                if (riemenkreisPunktY == nullPunkt)
                {
                    this.nachObenY = liste[5];
                    this.nachUntenY = liste[liste.Count - 10];
                    break;
                }
                liste.Add(riemenkreisPunktY);
            }
        }

        private void ErzeugeZylinderHuelle()
        {
            //  this.zylinderBreite = (int)this.kolbenBreite + (int)this.stangenLaenge;
            this.zylinderUntenRechtspkt = new Point(this.zylinderBreite, this.zylinderHoehe);
            //  float xposition = this.kreisMitteX + this.radius + this.kolbenBreite;
            float xposition = this.kreisMitteX - this.zylinderBreite / 2;
            float yposition = this.kreisMitteY - this.radius - this.zylinderHoehe - this.kolbenHoehe - 20;
            this.zylinderPosition = new Point((int)xposition, (int)yposition);
            this.zylinderHuelle = new Rectangle(this.zylinderPosition, new Size(this.zylinderUntenRechtspkt));
        }

        private void ErstelleKurbelWelle()
        {
            this.KurbelWelleRechtEck = new RectangleF(
                     this.kreisMitteX - this.radius, this.kreisMitteY - this.radius,
                     2 * this.radius, 2 * this.radius);
        }

        private void ErzeugeNockenWelle()
        {
            this.nockenWelleMitteX = this.kreisMitteX + this.radius + this.nockenWelleRadius + 20;
            this.nockenWelleMitteY = this.kreisMitteY;

            this.nockenWelleRechtEck = new RectangleF(
                this.nockenWelleMitteX - this.nockenWelleRadius, this.nockenWelleMitteY - this.nockenWelleRadius,
                this.nockenWelleRadius * 2, this.nockenWelleRadius * 2);

        }

        
        private void ErstelleKolben()
        {
            this.kolbenSize = new Size(this.kolbenBreite, this.kolbenHoehe);
            this.kolben = new Rectangle(this.kolbenPosition, this.kolbenSize);
        }

        private void OnPaint(object sender, PaintEventArgs e)
        {
            this.ZeichneSystem(e.Graphics);
            this.ZeichneZylinderhuelle(e.Graphics);

        }
        private void ZeichneSystem(Graphics graphics)
        {
            graphics.Clear(this.BackColor);
            graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            using (Pen stift = new Pen(Color.Blue, 2))
            {
                this.ZeichneKurbelWelle(graphics, stift);

                // Berechnen der Koordinaten auf dem Kreis.
                float kreisPunktX = (float)(this.kreisMitteX + Math.Cos(this.winkel) * this.radius);
                float kreisPunktY = (float)(this.kreisMitteY + Math.Sin(this.winkel) * this.radius);

                //Berchnen der Stangenposition.
                float stangenPunktY = this.BerechneStangenPosiY(kreisPunktX, kreisPunktY);
                float stangenPunktX = this.kreisMitteX;

                //Stange wird gezeichnet.
                this.ZeichnePleulStange(graphics, stift, kreisPunktX, kreisPunktY, stangenPunktX, stangenPunktY);
                //MittelKreis wird gezeichnet.
                graphics.FillEllipse(Brushes.Black, this.kreisMitteX - 4, this.kreisMitteY - 4, 8, 8);

                //Verbindungskreis auf der Kurbellwelle wird gezeichnet.
                graphics.FillEllipse(Brushes.Gray,
                    kreisPunktX - 4, kreisPunktY - 4, 8, 8);
                //Verbindungskreis auf der Stange wird gezeichnet
                graphics.FillEllipse(Brushes.Gray,
                    stangenPunktX - 4, stangenPunktY - 4, 8, 8);
                this.BerechneUndZeichneKolben(graphics, stangenPunktX, stangenPunktY);
                this.ZeichneNockenWelle(graphics, stift);

                float oben = this.kreisMitteY - this.radius;
               

            }
        }
        private void ZeichneKurbelWelle(Graphics graphics, Pen stift)
        {
            graphics.FillEllipse(Brushes.LightBlue, this.KurbelWelleRechtEck);
            stift.Color = Color.Black;
            stift.Width = 2;
            graphics.DrawEllipse(stift, this.KurbelWelleRechtEck);
        }
        /// <summary>
        /// Berechnet die Y-Koordinate der Pleustange anhand der Stangenlaenge
        /// und der x und y Koordinate auf der Kurbelwelle und gibt sie wieder.
        /// </summary>
        /// <param name="kreisX">X-Koordinate von einem Punkt auf dem Kreis.</param>
        /// <param name="kreisY">Y-Koordinate von einem Punkt auf dem Kreis.</param>
        /// <returns>Die Y-Koordinate der Pleustange.</returns>
        private float BerechneStangenPosiY(float kreisX, float kreisY)
        {
            float diff = 0.0F;
            float stangenLaengerqudrat = this.stangenLaenge * this.stangenLaenge;
            float erg = (stangenLaengerqudrat) - (kreisX * kreisX);//(k^2-xk^2)
            float erg2 = (float)Math.Sqrt(erg);//Wurzel aus (k^2-xk^2)
            float stangenPosyY = kreisY + erg2;//x + Wurzel aus (k^2-y^2)
            float momentaneLaenge = stangenPosyY - kreisY;
            if (stangenLaenge != momentaneLaenge)
            {
                diff = stangenLaenge - momentaneLaenge;

            }
            stangenPosyY = stangenPosyY + diff;
            return stangenPosyY - stangenLaenge * 2;
        }

        private void ZeichnePleulStange(Graphics graphics, Pen stift, float kreisPunktX, float kreisPunktY, float stangenPunktX, float stangenPunktY)
        {
            stift.Color = Color.Gray;
            stift.Width = 5;
            graphics.DrawLine(stift, kreisPunktX, kreisPunktY, stangenPunktX, stangenPunktY);
        }

        private void BerechneUndZeichneKolben(Graphics graphics, float stangenPosiX, float stangenPosiY)
        {
            int xPosi = (int)stangenPosiX - (int)this.kolbenBreite / 2;
            int yPosi = (int)stangenPosiY - (int)this.kolbenHoehe;
            this.kolbenPosition = new Point(xPosi, yPosi);
            this.kolben.Location = this.kolbenPosition;
            this.ZeichneKolben(graphics);
        }
        private void ZeichneKolben(Graphics graphics)
        {
            graphics.FillRectangle(Brushes.Gray, this.kolben);
        }

        private void ZeichneZylinderhuelle(Graphics g)
        {
            g.DrawRectangle(this.zylinderFarbe, this.zylinderHuelle);
        }
        private IList<Tuple<float, float>> test = new List<Tuple<float, float>>();

        private void ZeichneDreieck(Graphics g)
        {
            float dreicksKreisX1 = (float)(this.nockenWelleMitteX + Math.Cos(this.dreieckWinkel1) * this.dreieckKreisRadius);
            float dreicksKresY1 = (float)(this.nockenWelleMitteY + Math.Sin(this.dreieckWinkel1) * this.dreieckKreisRadius);

            float dreicksKreisX2 = (float)(this.nockenWelleMitteX + Math.Cos(this.dreieckWinkel2) * this.dreieckKreisRadius);
            float dreicksKresY2 = (float)(this.nockenWelleMitteY + Math.Sin(this.dreieckWinkel2) * this.dreieckKreisRadius);

            float dreieckEckPunktX = (float)(this.nockenWelleMitteX + Math.Cos(this.nockenWelleWinkel) * (this.nockenWelleRadius - 20));
            float dreieckEckPunktY = (float)(this.nockenWelleMitteY + Math.Sin(this.nockenWelleWinkel) * (this.nockenWelleRadius - 20));


            g.DrawLine(Pens.Black, dreicksKreisX1, dreicksKresY1, dreicksKreisX2, dreicksKresY2);
            g.DrawLine(Pens.Black, dreicksKreisX1, dreicksKresY1, dreieckEckPunktX, dreieckEckPunktY);
            g.DrawLine(Pens.Black, dreicksKreisX2, dreicksKresY2, dreieckEckPunktX, dreieckEckPunktY);
        }


        private void ZeichneNockenWelle(Graphics graphics, Pen stift)
        {
            graphics.FillEllipse(Brushes.LightBlue, this.nockenWelleRechtEck);
            stift.Color = Color.Blue;
            stift.Width = 2;
            graphics.DrawEllipse(stift, this.nockenWelleRechtEck);
            float riemenkreisPunktX = (float)(this.nockenWelleMitteX + Math.Cos(this.nockenWelleWinkel) * this.nockenWelleRadius);
            float riemenkreisPunktY = (float)(this.nockenWelleMitteY + Math.Sin(this.nockenWelleWinkel) * this.nockenWelleRadius);
            //graphics.FillEllipse(Brushes.Red,
            //        riemenkreisPunktX - 10, riemenkreisPunktY - 10, 20, 20);
            
            //this.ZeichneTaktZustand(graphics, this.takt);
            this.ZeichneDreieck(graphics);


            this.ErmittleTakt(riemenkreisPunktX, riemenkreisPunktY);
            if (riemenkreisPunktY < this.nachObenY && this.nachUntenY > riemenkreisPunktY)
            {
                this.ZeichneStange(graphics, true);
                this.ZeichneQuerStange(graphics, true);
            }
            else
            {
                this.ZeichneStange(graphics, false);
                this.ZeichneQuerStange(graphics, false);
            }
            this.ZeichneTaktZustand(graphics, this.takt);

        }

        private void ZeichneStange(Graphics g, bool oben)
        {
            if (oben)
            {
                this.stange.Location = this.stangenPosiOben;
            }
            else
            {
                this.stange.Location = this.stangenPosiUnten;
            }
            g.DrawRectangle(Pens.Black, this.stange);
        }

        private void ZeichneQuerStange(Graphics g, bool unten)
        {
            int ywert;
            if (unten)
            {
                ywert = this.stange.Y + 10;
            }
            else
            {
                ywert = this.stange.Y;
            }
            g.DrawLine(Pens.Black, this.stange.Right, this.stange.Y, this.kreisMitteX, ywert);
            g.DrawLine(Pens.Black, this.kreisMitteX, ywert, this.kreisMitteX, ywert + 15);
            g.DrawLine(Pens.Black, this.kreisMitteX - 5, ywert + 15, this.kreisMitteX + 5, ywert + 15);
        }


        private void ErmittleTakt(float kurbelWellePunktX, float kurbelWellePunktY)
        {
            float bla;


            if (this.ansaugPunktY == kurbelWellePunktY)
            {
                this.takt = Takt.AnsaugTakt;
                bla = this.nockenWelleWinkel;
            }
            if (this.verdichtungsPunktX == kurbelWellePunktX)
            {
                this.takt = Takt.VerdichtungsTakt;
                bla = this.nockenWelleWinkel;
            }
            if (this.explosionsPunktY == kurbelWellePunktY)
            {
                this.takt = Takt.ExplosionsTakt;
                bla = this.nockenWelleWinkel;
            }
            if (this.absaubungsPunktX == kurbelWellePunktX)
            {
                this.takt = Takt.AbsaugTakt;
                bla = this.nockenWelleWinkel;

            }
            // return Takte.DerSelbe;

        }


        private void BerechneTaktPunkte()
        {
            this.ansaugPunktY = this.nockenWelleMitteY - this.nockenWelleRadius;
            this.verdichtungsPunktX = this.nockenWelleMitteX + this.nockenWelleRadius;

            this.explosionsPunktY = this.nockenWelleMitteY + this.nockenWelleRadius;
            this.absaubungsPunktX = this.nockenWelleMitteX - this.nockenWelleRadius;
        }


        private void ZeichneTaktZustand(Graphics graphics, Takt momentanerTakt)
        {
            switch (momentanerTakt)
            {
                case Takt.AnsaugTakt:
                   
                    this.label1.Text = "1.Takt Ansaugen";                   
                  
                    break;
                case Takt.VerdichtungsTakt:
                 
                    this.label1.Text = "2.Takt Verdichten";
                    graphics.FillRectangle(Brushes.Blue, this.kolben.Right, this.kolben.Y,
                        this.zylinderHuelle.Right - this.kolben.Right, this.zylinderHoehe);
                    
                    break;
                case Takt.ExplosionsTakt:
                  
                    this.label1.Text = "3.Takt Arbeiten";
                    graphics.FillRectangle(Brushes.Orange, this.kolben.Right, this.kolben.Y,
                        this.zylinderHuelle.Right - this.kolben.Right, this.zylinderHoehe);
                  
                    break;
                case Takt.AbsaugTakt:                   
                    this.label1.Text = "4.Takt Auslassen";                  
                 
                    break;
            }

        }
    }
}
